﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "NewViewProfileEditModeBehavior.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IDocument.h"
#include "IGenericType.h"
#include "IGenericElement.h"
#include "IEditMode.h"
#include "ILevel.h"
#include "GbmpPlanViewInput.h"
#include "IGbmpPlanView.h"
#include "IModelView.h"
#include "NewViewProfileEditModeGRepFilter.h"
#include "ReferencePlaneUtils.h"
#include "IReferencePlane.h"
#include "ReferencePlaneType.h"
#include "IElementBasicInformation.h"
#include "IModelLine.h"
#include "IElementParentReporter.h"
#include "StructureEditModeTypes.h"
#include "ProfileUsedModelLineUtils.h"
#include "GbmpDocUtils.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DBOBJECT_DATA_DEFINE(NewViewProfileEditModeBehavior)
{
}

NewViewProfileEditModeBehavior::~NewViewProfileEditModeBehavior()
{
}

bool NewViewProfileEditModeBehavior::StartEditing(gcmp::IDocument* pDoc, bool isCreating)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // 获取一个标高类型
    ElementId levelTypeId;
    std::vector<IElement*> pElements = gcmp::GbmpDocUtils::GetElementsByCategory(pDoc, BuiltInCategoryUniIdentities::BICU_NEW_LEVEL_TYPE);
    FOR_EACH(pElement, pElements)
    {
        if (IGenericType* pLevelType = quick_cast<IGenericType>(pElement))
        {
            levelTypeId = pLevelType->GetElementId();
            break;
        }
    }

    // 视图高度
    double height = 0.0;
    // 创建视图所在标高
    ILevel* pLevel = ILevel::Create(pDoc, levelTypeId, GBMP_TR(L"轮廓视图标高"),
        Vector3d(-1000.0, 0, height), Vector3d(1000.0, 0, height), Vector3d::UnitY, ElementId::InvalidID);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pLevel, L"楼层创建失败",L"GDMPLab",L"2024-03-30");

    // 创建视图
    GbmpPlanViewInput planViewInput;
    planViewInput.Document = pDoc;
    planViewInput.Name = pLevel->GetName();
    planViewInput.Level = pLevel;
    planViewInput.HasRectViewport = false;
    IGbmpPlanView* pPlanView = IGbmpPlanView::Create(planViewInput);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pPlanView, L"pPlanView为空",L"GDMPLab",L"2024-03-30");
    // 视图过滤
    IModelView* pModelView = pPlanView->GetModelView();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    pModelView->AddElementVisibilityFilter(NEW_AS_OWNER_PTR(NewViewProfileEditModeGRepFilter));

    // 添加默认的参照平面，并设置固定
    double referencePlaneLength = 2500;
    Coordinate3d coordXOY(Vector3d::Zero, Vector3d::UnitX, Vector3d::UnitY);
    Vector3d startPtX(-referencePlaneLength, 0, height);
    Vector3d endPtX(referencePlaneLength, 0, height);
    IReferencePlane* pReferencePlaneX = ReferencePlaneUtils::CreateByPoints(pDoc, startPtX, endPtX, Vector3d::UnitZ);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pReferencePlaneX, L"创建参照平面失败",L"GDMPLab",L"2024-03-30");
    pReferencePlaneX->SetReferencePlaneType(ReferencePlaneType::UserDefined);
    pReferencePlaneX->SetVisibleUVMin(Vector2d(-referencePlaneLength, -referencePlaneLength));
    pReferencePlaneX->SetVisibleUVMax(Vector2d(referencePlaneLength, referencePlaneLength));
    pReferencePlaneX->GetBasicInformation()->SetName(GBMP_TR(L"X轴"));
    pReferencePlaneX->SetIsFixed(true);

    Vector3d startPtY(0, -referencePlaneLength, height);
    Vector3d endPtY(0, referencePlaneLength, height);
    IReferencePlane* pReferencePlaneY = ReferencePlaneUtils::CreateByPoints(pDoc, startPtY, endPtY, Vector3d::UnitZ);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pReferencePlaneY, L"创建参照平面失败",L"GDMPLab",L"2024-03-30");
    pReferencePlaneY->SetReferencePlaneType(ReferencePlaneType::UserDefined);
    pReferencePlaneY->SetVisibleUVMin(Vector2d(-referencePlaneLength, -referencePlaneLength));
    pReferencePlaneY->SetVisibleUVMax(Vector2d(referencePlaneLength, referencePlaneLength));
    pReferencePlaneY->GetBasicInformation()->SetName(GBMP_TR(L"Y轴"));
    pReferencePlaneY->SetIsFixed(true);

    // 设置ElementId
    SetLevelId(pLevel->GetOwnerElement()->GetElementId());
    SetModelViewId(pPlanView->GetElementId());
    SetReferencePlaneXId(pReferencePlaneX->GetElementId());
    SetReferencePlaneYId(pReferencePlaneY->GetElementId());

    return true;
}

bool NewViewProfileEditModeBehavior::EndEditing(gcmp::IDocument* pDoc)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // 结束编辑模式时删除临时对象（标高、视图、参考平面）
    this->CleanUp(pDoc);

    return true;
}

std::wstring NewViewProfileEditModeBehavior::GetEditModeType() const
{
    return StructureEditModeTypes::NewViewCustomizedProfileModeType;
}


bool NewViewProfileEditModeBehavior::IsElementEditable(const IElement* pElement) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");

    // 作为轮廓的模型线可以编辑
    if (ProfileUsedModelLineUtils::IsModelLineUsedForProfile(pElement))
    {
        return true;
    }

    return false;
}

void NewViewProfileEditModeBehavior::ReportParents(IDocument* pDoc, IElementParentReporter& reporter) const
{
    reporter.ReportWeak(GetLevelId());
    reporter.ReportWeak(GetModelViewId());
    reporter.ReportWeak(GetReferencePlaneXId());
    reporter.ReportWeak(GetReferencePlaneYId());
}

void NewViewProfileEditModeBehavior::UpdateForWeakParentDeletion(IDocument* pDoc, const std::set<ElementId>& deletedElementIds)
{
    IEditMode* pProfileEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pProfileEditMode, L"pProfileEditMode为空",L"GDMPLab",L"2024-03-30");
    
    if (deletedElementIds.find(pProfileEditMode->GetEditingElementId()) != deletedElementIds.end())
    {
        DBG_WARN(L"不应该在EditMode有效时删除其中引用的Element",L"GDMPLab",L"2024-03-30");
    }

    if (deletedElementIds.find(GetLevelId()) != deletedElementIds.end())
    {
        SetLevelId(ElementId::InvalidID);
    }
    if (deletedElementIds.find(GetModelViewId()) != deletedElementIds.end())
    {
        SetModelViewId(ElementId::InvalidID);
    }
    if (deletedElementIds.find(GetReferencePlaneXId()) != deletedElementIds.end())
    {
        SetReferencePlaneXId(ElementId::InvalidID);
    }
    if (deletedElementIds.find(GetReferencePlaneYId()) != deletedElementIds.end())
    {
        SetReferencePlaneYId(ElementId::InvalidID);
    }
}

bool NewViewProfileEditModeBehavior::CleanUp(IDocument* pDoc)
{
    if (GetLevelId().IsValid())
    {
        bool bOk = pDoc->DeleteElement(GetLevelId());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"删除临时对象失败",L"GDMPLab",L"2024-03-30");
    }
    if (GetModelViewId().IsValid())
    {
        bool bOk = pDoc->DeleteElement(GetModelViewId());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"删除临时对象失败",L"GDMPLab",L"2024-03-30");
    }
    if (GetReferencePlaneXId().IsValid())
    {
        bool bOk = pDoc->DeleteElement(GetReferencePlaneXId());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"删除临时对象失败",L"GDMPLab",L"2024-03-30");
    }
    if (GetReferencePlaneYId().IsValid())
    {
        bool bOk = pDoc->DeleteElement(GetReferencePlaneYId());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"删除临时对象失败",L"GDMPLab",L"2024-03-30");
    }
    return true;
}
